package com.myrpc.client;

import java.lang.reflect.Proxy;
import java.util.UUID;

import com.myrpc.common.Req;
import com.myrpc.common.Res;
import com.myrpc.constant.Constant;
import com.myrpc.handler.RpcClientHandler;
import com.myrpc.handler.RpcDecoder;
import com.myrpc.handler.RpcEncoder;
import com.myrpc.provider.UserInfo;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

/**
 * Created with IntelliJ IDEA.
 *
 * @Description:
 * @User: weiyi.liu
 * @Date: 2018-06-08
 * @Time: 22:23
 */
public class ConsumerMgr {
	public static void main(String[] args) {
		UserInfo userInfo = createProxy(UserInfo.class, (short) 2);
		String ss = userInfo.getUserName("ssssss");
		System.err.println(ss);
	}

	/**
	 * 创建代理对象
	 * 
	 * @param clazz 被代理的对象类
	 * @param version 版本
	 * @param <T>
	 * @return 代理对象
	 */
	private static <T> T createProxy(Class<T> clazz, short version) {
		return (T) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[] { clazz }, (proxy, method, args) -> {
			Req req = new Req();
			req.setId(UUID.randomUUID().toString());
			req.setClassName(method.getDeclaringClass().getSimpleName());
			req.setMethodName(method.getName());
			req.setParams(args);
			req.setParamsTypes(method.getParameterTypes());
			req.setVersion(version);
			return send(req);
		});
	}

	/**
	 * 想Service请求远程调用
	 * 
	 * @param req 请求数据
	 * @return
	 */
	private static Object send(Req req) {
		NioEventLoopGroup group = null;
		try {
			group = new NioEventLoopGroup();
			RpcClientHandler rpcClientHandler = new RpcClientHandler();
			Bootstrap bootstrap = new Bootstrap();
			bootstrap.group(group);
			bootstrap.channel(NioSocketChannel.class);
			bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
			bootstrap.handler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel socketChannel) {
					ChannelPipeline pipeline = socketChannel.pipeline();
					pipeline.addLast(new RpcEncoder(Req.class));
					pipeline.addLast(new RpcDecoder(Res.class));
					pipeline.addLast(rpcClientHandler);
				}
			});
			ChannelFuture future = bootstrap.connect("127.0.0.1", Constant.SERVICE_PORT).sync();
			synchronized (rpcClientHandler.obj) {
				future.channel().writeAndFlush(req).sync();
				rpcClientHandler.obj.wait();
			}
			future.channel().closeFuture().sync();
			return rpcClientHandler.res.getData();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			group.shutdownGracefully();
		}
		return null;
	}
}
